package nautilus.tank.model;

import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.imageio.ImageIO;

import nautilus.tank.Constant;

/**
	This class also acts as game coordinator
	
	Author: Dao Anh Vu
*/
public class Game {
	private String name;
	private List<Player> players = new ArrayList<Player>();
	private List<IBattleObject> objects;
	
	/** width, height by pixel */
	private int width;
	/** width, height by pixel */
	private int height;
	
	/** width, height by tile */
	private int heightByTile = 23;
	/** width, height by tile */
	private int widthByTile = 35;
	private int tileWidth = 32;
	
	private BufferedImage mapImage;
	private byte[][] mapData;
	
	//viewport
	private int left, top, right, bottom;
	
	private int X0, Y0, Z0;
	
	//for easier calculating, here I define that the ratio of pixels/m
	private int scaleFactor = 10;
	
	private IBattleObject selectedObject = null;
	
	public Game(){
		left = top = right = bottom = 0;
		X0 = Y0 = Z0 = 0;
		//Load default map
		width = tileWidth * widthByTile; 
		height = tileWidth * heightByTile;
		mapData = new byte[][]{
				{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1, 1, 1},
				{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1, 1, 1},
				{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1, 1, 1},
				{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,10,12,1,1,1,1, 1, 1, 1},
				{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,10,12,1,1,1,1, 1, 1, 1},
				{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,10,12,1,1,1,1, 1, 1, 1},
				{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,10,12,1,1,1,1, 1, 1, 1},
				{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,10,1,1,1,1,1,1,1,1,10,12,1,1,1, 1, 1, 1},
				{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,10,11,1,1,1,1,1,1,1,10,12,1,1,1,1, 1, 1, 1},
				{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,10,11,11,11,1,1,1,1,1,12,1,1,1,1,1,1, 1, 1, 1},
				{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,11,11,11,11,1,1,1,1,1,1,1,1,1,1,1,1, 1, 1, 1},
				{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,11,11,11,11,11,1,1,1,1,1,1,1,1,1,1,1, 1, 1, 1},
				{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,11,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1, 1, 1},
				{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,11,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1, 1, 1},
				{1,1,1,1,1,1,1,1,1,1,1,1,1,1,10,11,6,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1, 1, 1},
				{1,1,1,1,1,1,1,1,1,1,1,1,1,10,11,6,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1, 1, 1},
				{1,1,1,1,1,1,1,1,1,1,1,1,10,11,6,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1, 1, 1},
				{1,1,1,1,1,1,1,1,1,1,1,10,11,6,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1, 1, 1},
				{1,1,1,1,1,1,1,1,1,1,10,11,6,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1, 1, 1},
				{1,1,1,1,1,1,1,1,1,1,10,11,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1, 1, 1},
				{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1, 1, 1},
				{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1, 1, 1},
				{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,14, 1, 1, 1}
				};
		/*
		mapData = new byte[heightByTile][widthByTile];
		for(int i=0;i<heightByTile;i++){
			for(int j=0;j<widthByTile;j++){
				mapData[i][j] = 1;
			}
		}
		*/
		initMapImage();
		players.add(new Player());
		
		objects = new ArrayList<IBattleObject>();
		objects.addAll(players.get(0).getVehicles());
		
	}
	
	public void setName(String name){
		this.name = name;
	}
	
	public String getName(){
		return this.name;
	}
	
	public List<IBattleObject> getObjects(){
		return objects;
	}
	
	public IBattleObject getSelectedObject(){
		return selectedObject;
	}
	
	public void setSelectedObject(IBattleObject obj){
		if(obj != selectedObject){
			if(selectedObject != null)
				selectedObject.setSelected(false);
			selectedObject = obj;
			selectedObject.setSelected(true);
		}
	}
	
	public List<Player> getPlayes(){
		return players;
	}
	
	public void load(String path)throws IOException{
		FileInputStream fis = null;
		try{
			DataInputStream inputStream = new DataInputStream(fis);
			
			
		}finally{
			if(fis != null)
				fis.close();
		}
	}
	
	public void save(String path)throws IOException{
		FileOutputStream fos = null;
		try{
			DataOutputStream dos = new DataOutputStream(fos);
			dos.writeInt(widthByTile);
			dos.writeInt(heightByTile);
			for(int i=0; i<heightByTile; i++){
				dos.write(mapData[i]);
			}
			dos.flush();
		}finally{
			if(fos != null)
				fos.close();
		}
	}
	
	private void initMapImage(){
		
		Image[] map = new Image[15];
		try {
			for(int i=1;i<16;i++){
				map[i-1] = ImageIO.read(new File(Constant.EXECUTING_FOLDER, "mapTile" + i + ".png"));
			}
			mapImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
			Graphics2D g2 = mapImage.createGraphics();
			for(int i=0;i<heightByTile;i++){
				for(int j=0;j<widthByTile;j++){
					g2.drawImage(map[ mapData[i][j]-1 ], X0 + j * tileWidth, Y0 + i * tileWidth, 
							tileWidth, tileWidth, null);
				}
			}
			g2.dispose();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	

	//TODO: fix this
	public byte getMapDataAt(float x, float y){
		return mapData[(int)x/tileWidth][(int)y/tileWidth];
	}
	
	public void renderMap(Graphics2D g){
		g.drawImage(mapImage, X0, Y0, width, height, null);
	}
	
	//I'm not sure why it should be here
	public boolean collisionDectect(IBattleObject aObj){
		float[] p;
		for(IBattleObject obj: objects){
			
			p = aObj.getLeftTop();
			if( obj.isInsideShape(p[0], p[1]) )
				return true;
			
			p = aObj.getRightTop();
			if( obj.isInsideShape(p[0], p[1]) )
				return true;
			
			p = aObj.getLeftBottom();
			if( obj.isInsideShape(p[0], p[1]) )
				return true;
			
			p = aObj.getRightBottom();
			if( obj.isInsideShape(p[0], p[1]) )
				return true;
		}
		
		return false;
	}
}
